package logic_spa

import (
	"APT/internal/consts"
	"APT/internal/dao"
	"APT/internal/library/contexts"
	"APT/internal/library/hgorm"
	"APT/internal/library/hgorm/handler"
	hook2 "APT/internal/library/hgorm/hook"
	"APT/internal/model/entity"
	"APT/internal/model/input/input_basics"
	"APT/internal/model/input/input_refund"
	"APT/internal/model/input/input_spa"
	"APT/internal/service"
	"APT/utility/format"
	"APT/utility/rabbitmq"
	"context"
	"database/sql"
	"errors"
	"fmt"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/shopspring/decimal"
	"strconv"
	"strings"
	"time"
)

type sSpaOrder struct{}

func NewSpaOrder() *sSpaOrder {
	return &sSpaOrder{}
}

func init() {
	service.RegisterSpaOrder(NewSpaOrder())
}

func (s *sSpaOrder) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
	return handler.Model(dao.SpaOrder.Ctx(ctx), option...)
}

func (s *sSpaOrder) List(ctx context.Context, in *input_spa.SpaOrderListInp) (list []*input_spa.SpaOrderListModel, totalCount int, err error) {
	mod := s.Model(ctx).WithAll()

	mod = mod.FieldsPrefix(dao.SpaOrder.Table(), input_spa.SpaOrderListModel{})
	mod = mod.Fields(hgorm.JoinFields(ctx, input_spa.SpaOrderListModel{}, &dao.PmsMember, "pmsMember"))

	mod = mod.LeftJoinOnFields(dao.PmsMember.Table(), dao.SpaOrder.Columns().MemberId, "=", dao.PmsMember.Columns().Id)

	if !g.IsEmpty(in.OrderSn) {
		mod = mod.WhereLike(dao.SpaOrder.Columns().OrderSn, "%"+in.OrderSn+"%")
	}

	if !g.IsEmpty(in.TechnicianName) {
		var (
			technicianIds []gdb.Value
			orderIds      []gdb.Value
		)
		technicianIds, err = dao.SpaTechnician.Ctx(ctx).Where(dao.SpaTechnician.Ctx(ctx).Builder().
			WhereLike(dao.SpaTechnician.Columns().Name, "%"+in.TechnicianName+"%").
			WhereOrLike(dao.SpaTechnician.Columns().Nickname, "%"+in.TechnicianName+"%")).Array(dao.SpaTechnician.Columns().Id)

		if len(technicianIds) > 0 {
			orderIds, err = dao.SpaOrderTechnician.Ctx(ctx).WhereIn(dao.SpaOrderTechnician.Columns().TechnicianId, technicianIds).Array(dao.SpaOrderTechnician.Columns().OrderId)
			if len(orderIds) > 0 {
				mod = mod.WherePrefixIn(dao.SpaOrder.Table(), dao.SpaOrder.Columns().Id, orderIds)
			} else {
				mod = mod.WherePrefix(dao.SpaOrder.Table(), dao.SpaOrder.Columns().Id, 0)
			}
		} else {
			mod = mod.WherePrefix(dao.SpaOrder.Table(), dao.SpaOrder.Columns().Id, 0)
		}
	}
	if !g.IsEmpty(in.MemberSearch) {
		mod = mod.Where(mod.Builder().
			WhereLike(dao.PmsMember.Columns().Id, "%"+in.MemberSearch+"%").
			WhereOrLike(dao.PmsMember.Columns().MemberNo, "%"+in.MemberSearch+"%").
			WhereOrLike(dao.SpaOrder.Columns().BookingName, "%"+in.MemberSearch+"%").
			WhereOrLike(dao.SpaOrder.Columns().BookingMobile, "%"+in.MemberSearch+"%"))
	}

	if !g.IsEmpty(in.OrderStatus) && in.OrderStatus != "ALL" {
		mod = mod.Where(dao.SpaOrder.Columns().OrderStatus, in.OrderStatus)
	}

	mod = mod.Page(in.Page, in.PerPage)

	mod = mod.OrderDesc(dao.SpaOrder.Columns().Id)
	mod = mod.Hook(hook2.PmsFindLanguageValueHook)

	if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
		err = gerror.Wrap(err, "获取预订单列表失败，请稍后重试！")
		return
	}
	return
}

func (s *sSpaOrder) View(ctx context.Context, in *input_spa.SpaOrderViewInp) (res *input_spa.SpaOrderViewModel, err error) {
	if err = s.Model(ctx).WithAll().Where(dao.SpaOrder.Columns().OrderSn, in.OrderSn).Hook(hook2.PmsFindLanguageValueHook).Scan(&res); err != nil {
		err = gerror.Wrap(err, "获取预订单信息，请稍后重试！")
		return
	}

	return
}

func (s *sSpaOrder) ConfirmAgree(ctx context.Context, in *input_spa.SpaOrderConfirmAgreeInp) (err error) {

	var models *entity.SpaOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "WAIT_CONFIRM" {
		err = gerror.New("订单状态不正确")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		if _, err = s.Model(ctx).
			WherePri(in.Id).Data(input_spa.SpaOrderConfirmAgreeFields{
			OrderStatus: "WAIT_SERVE",
			ConfirmTime: gtime.Now(),
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		if _, err = dao.SpaOrderGoods.Ctx(ctx).Where(dao.SpaOrderGoods.Columns().OrderId, in.Id).Update(g.MapStrAny{
			dao.SpaOrderGoods.Columns().OrderStatus: "WAIT_SERVE",
		}); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     in.Id,
			OrderStatus: "WAIT_SERVE",
			ActionWay:   "CONFIRMED",
			Remark:      "系统已自动接单",
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}
		return
	})

}

// ConfirmDisagree 确认失败，全额退款
func (s *sSpaOrder) ConfirmDisagree(ctx context.Context, in *input_spa.SpaOrderConfirmDisagreeInp) (err error) {

	var models *entity.SpaOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "WAIT_CONFIRM" {
		err = gerror.New("订单状态不正确")
		return
	}

	if models.RefundStatus != "WAIT" {
		err = gerror.New("订单已退款")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {

		// 改变订单确认状态
		if _, err = s.Model(ctx).TX(tx).
			WherePri(in.Id).Data(input_spa.SpaOrderConfirmDisagreeFields{
			BookingStatus:       "CANCEL",
			ConfirmRefuseReason: in.ConfirmRefuseReason,
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     in.Id,
			OrderStatus: "CANCEL",
			ActionWay:   "DISCONFIRMED",
			Remark:      fmt.Sprintf("系统拒绝接单，原因：%s", in.ConfirmRefuseReason),
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		// 确认失败、全额退款
		// 计算退款金额
		var (
			Transaction       []*entity.PmsTransaction
			TransactionRefund []*entity.PmsTransactionRefund
			RefundBalance     float64 // 可退款积分
			RefundFee         float64 // 第三方支付
		)
		if err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(dao.PmsTransaction.Columns().OrderSn, models.OrderSn).Scan(&Transaction); err != nil {
			return
		}
		if err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).Where(dao.PmsTransactionRefund.Columns().OrderSn, models.OrderSn).Scan(&TransactionRefund); err != nil {
			return
		}

		for _, v := range Transaction {
			// 可退款金额
			Refundable := v.Amount - v.RefundAmount
			if v.PayType == "BAL" {
				RefundBalance = RefundBalance + Refundable
			} else if v.PayType == "COUPON" {

			} else {
				RefundFee = RefundFee + Refundable
			}
		}
		// 退款金额
		RefundAmount := RefundBalance + RefundFee

		// 修改订单状态
		RefundStatus := "DONE"
		if models.OrderAmount > RefundAmount {
			RefundStatus = "PART"
		}
		if _, err = s.Model(ctx).TX(tx).
			WherePri(in.Id).Data(g.MapStrAny{
			dao.SpaOrder.Columns().RefundAmount:       RefundAmount,
			dao.SpaOrder.Columns().RefundBalAmount:    RefundBalance,
			dao.SpaOrder.Columns().RefundCouponAmount: 0,
			dao.SpaOrder.Columns().RefundStatus:       RefundStatus,
			dao.SpaOrder.Columns().RefundTime:         gtime.Now(),
			dao.SpaOrder.Columns().OrderStatus:        "CANCEL",
			dao.SpaOrder.Columns().PayStatus:          "REFUND",
			dao.SpaOrder.Columns().CancelTime:         gtime.Now(),
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		if _, err = dao.SpaOrderGoods.Ctx(ctx).TX(tx).Where(dao.SpaOrderGoods.Columns().OrderId, in.Id).Update(g.MapStrAny{
			dao.SpaOrderGoods.Columns().RefundAmount:       RefundAmount,
			dao.SpaOrderGoods.Columns().RefundBalAmount:    RefundBalance,
			dao.SpaOrderGoods.Columns().RefundCouponAmount: 0,
			dao.SpaOrderGoods.Columns().RefundStatus:       RefundStatus,
			dao.SpaOrderGoods.Columns().RefundTime:         gtime.Now(),
			dao.SpaOrderGoods.Columns().OrderStatus:        "CANCEL",
			dao.SpaOrderGoods.Columns().PayStatus:          "REFUND",
		}); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 更新服务预定量和预定金额
		if _, err = dao.SpaService.Ctx(ctx).TX(tx).Where(dao.SpaService.Columns().Id, models.ServiceId).Update(g.MapStrAny{
			dao.SpaService.Columns().PayOrderNum:    gdb.Raw("pay_order_num-1"),
			dao.SpaService.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
		}); err != nil {
			err = gerror.Wrap(err, "更新服务信息失败，请稍后重试！")
			return
		}

		// 更新项目预定量和预定金额
		if _, err = dao.SpaServiceGoods.Ctx(ctx).TX(tx).Where(dao.SpaServiceGoods.Columns().Id, models.GoodsId).Update(g.MapStrAny{
			dao.SpaServiceGoods.Columns().PayOrderNum:    gdb.Raw(fmt.Sprintf("pay_order_num-%d", models.GoodsNum)),
			dao.SpaServiceGoods.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
		}); err != nil {
			err = gerror.Wrap(err, "更新项目信息失败，请稍后重试！")
			return
		}

		//// 更新技师预定量和预定金额
		//if !g.IsEmpty(models.TechnicianIds) {
		//	for _, Technician := range strings.Split(models.TechnicianIds, ",") {
		//		if !g.IsEmpty(Technician) {
		//			TechnicianId, _ := strconv.ParseInt(Technician, 10, 64)
		//			// 更新技师预定量和预定金额
		//			if _, err = dao.SpaTechnician.Ctx(ctx).Where(dao.SpaTechnician.Columns().Id, TechnicianId).Update(g.MapStrAny{
		//				dao.SpaTechnician.Columns().PayOrderNum:    gdb.Raw(fmt.Sprintf("pay_order_num-%d", 1)),
		//				dao.SpaTechnician.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", models.OrderAmount/float64(models.GoodsNum))),
		//			}); err != nil {
		//				err = gerror.Wrap(err, "更新技师信息失败，请稍后重试！")
		//				return
		//			}
		//		}
		//	}
		//}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     in.Id,
			OrderStatus: "CANCEL",
			ActionWay:   "REFUND",
			Remark:      "订单已退款",
			OperateType: "SYSTEM",
		}); err != nil {
			return err
		}

		// 全额退款
		err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
			OrderSn:      models.OrderSn,
			RefundAmount: RefundAmount,
		}, tx)
		if err != nil {
			err = gerror.Wrap(err, "退款操作失败，请稍后重试！")
			return
		}

		return
	})

}

func (s *sSpaOrder) TechnicianList(ctx context.Context, in *input_spa.SpaOrderTechnicianInp) (list []*input_spa.SpaOrderTechnicianModel, totalCount int, err error) {
	var (
		OrderInfo       *entity.SpaOrder
		NoTechnicianIds []string
		CheckOrderList  []*entity.SpaOrder
		Config          *input_basics.GetConfigModel
		BeforeTime      int
		OrderBeforeTime int
	)
	if err = dao.SpaOrder.Ctx(ctx).Where(dao.SpaOrder.Columns().Id, in.Id).Scan(&OrderInfo); err != nil {
		return
	}

	techMod := dao.SpaTechnician.Ctx(ctx)
	techMod = techMod.Fields(input_spa.SpaOrderTechnicianModel{})

	if !g.IsEmpty(OrderInfo.IspId) {
		techMod = techMod.Where(dao.SpaTechnician.Columns().IspId, OrderInfo.IspId)
	}

	//if OrderInfo.ConfirmType == 1 {
	// 手动确认
	Config, err = service.BasicsConfig().GetConfigByGroup(ctx, &input_basics.GetConfigInp{
		Group: "spaordersetting",
	})
	if err != nil {
		return
	}
	OrderMode := Config.List["orderMode"]
	ServiceTimeDuration := Config.List["serviceTimeDuration"]
	OutWorkTimeDuration := Config.List["outWorkTimeDuration"]
	if gvar.New(OrderMode).Int() == 2 {
		if OrderInfo.ServiceType == 1 {
			BeforeTime = gvar.New(ServiceTimeDuration).Int()
		} else {
			BeforeTime = gvar.New(ServiceTimeDuration).Int() + gvar.New(OutWorkTimeDuration).Int()
		}
		StartTime := gtime.New(OrderInfo.BookStartTime).Add(time.Duration(-BeforeTime) * gtime.M).Timestamp()
		// 找出订单预约当天的已被派单的且处于待服务或服务中状态的订单
		if err = dao.SpaOrder.Ctx(ctx).Where(dao.SpaOrder.Columns().BookDate, OrderInfo.BookDate).WhereNot(dao.SpaOrder.Columns().Id, in.Id).WhereIn(dao.SpaOrder.Columns().OrderStatus, g.Slice{"WAIT_SERVE", "SERVING"}).Where(dao.SpaOrder.Columns().DispatchStatus, "DONE").Scan(&CheckOrderList); err != nil {
			return
		}

		// 遍历订单
		for _, v := range CheckOrderList {
			if v.ServiceType == 1 {
				OrderBeforeTime = gvar.New(ServiceTimeDuration).Int()
			} else {
				OrderBeforeTime = gvar.New(ServiceTimeDuration).Int() + gvar.New(OutWorkTimeDuration).Int()
			}
			OrderStartTime := gtime.New(v.BookStartTime).Add(time.Duration(-OrderBeforeTime) * gtime.M).Timestamp()
			if gtime.New(v.BookEndTime).Timestamp() <= StartTime || OrderStartTime >= gtime.New(OrderInfo.BookEndTime).Timestamp() {

			} else {
				technicianId := strings.Split(v.TechnicianIds, ",")
				for _, vv := range technicianId {
					technicianIdString := gvar.New(vv).String()
					NoTechnicianIds = append(NoTechnicianIds, technicianIdString)
				}
			}
		}
		NoTechnicianIdsStr := strings.Join(NoTechnicianIds, ",")
		if g.IsEmpty(NoTechnicianIdsStr) {
			NoTechnicianIdsStr = "0"
		}
		techMod = techMod.WhereNot(dao.SpaTechnician.Columns().WorkStatus, "REST").Where(dao.SpaTechnician.Columns().Status, 1)
		techMod = techMod.Fields(fmt.Sprintf(`
	CASE
        WHEN work_status='REST' THEN 1
        WHEN id IN(%s) THEN 2
        ELSE 3
    END AS work_status_enum
`, NoTechnicianIdsStr))
		techMod = techMod.Where(dao.SpaTechnician.Columns().Status, 1)
		techMod = techMod.OrderDesc(fmt.Sprintf(`
	CASE
        WHEN work_status='REST' THEN 1
        WHEN id IN(%s) THEN 2
        ELSE 3
    END
`, NoTechnicianIdsStr))
	} else {
		techMod = techMod.Where(dao.SpaTechnician.Columns().Status, 1)
		techMod = techMod.Fields(fmt.Sprintf(`
	CASE
        WHEN id > %d THEN 3
        ELSE 3
    END AS work_status_enum
`, 0))
	}

	//} else {
	//	techMod = techMod.Where(dao.SpaTechnician.Columns().Status, 1)
	//}
	// 分页
	if in.Pagination {
		techMod = techMod.Page(in.Page, in.PerPage)
	}
	if in.Pagination {
		if err = techMod.ScanAndCount(&list, &totalCount, false); err != nil && !errors.Is(err, sql.ErrNoRows) {
			err = gerror.Wrap(err, "获取技师列表失败，请稍后重试！")
			return
		}
	} else {
		if err = techMod.Scan(&list); err != nil && !errors.Is(err, sql.ErrNoRows) {
			err = gerror.Wrap(err, "获取技师列表失败，请稍后重试！")
			return
		}
	}
	return
}

func (s *sSpaOrder) Dispatch(ctx context.Context, in *input_spa.SpaOrderDispatchInp) (err error) {

	var (
		models                *entity.SpaOrder
		OrderGoods            *entity.SpaOrderGoods
		TechnicianInfo        *entity.SpaTechnician
		CheckOrderList        []*entity.SpaOrder
		Config                *input_basics.GetConfigModel
		IspSettlementRate     float64
		IspSettlementObject   string
		BeforeTime            int
		OrderBeforeTime       int
		CantOrderNum          int
		OrderTechnicianInfo   []*entity.SpaOrderTechnician
		TechnicianSettlement  *input_spa.SpaOrderDispatchTechnicianModel
		IspSettlement         *input_spa.SpaOrderDispatchIspModel
		ActualSettlementRate  float64
		ActualSettlementType  int
		ActualSettlementCycle int
		ActualSettlementCost  string
	)
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "WAIT_SERVE" || models.DispatchStatus != "WAIT" {
		err = gerror.New("订单状态不正确")
		return
	}

	if err = dao.SpaOrderGoods.Ctx(ctx).Where("order_id", in.Id).Scan(&OrderGoods); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models.IspId > 0 {
		if err = dao.SpaIsp.Ctx(ctx).WithAll().Where("id", models.IspId).Scan(&IspSettlement); err != nil {
			err = gerror.Wrap(err, consts.ErrorORM)
			return
		}

		if IspSettlement.SettlementType == 1 {
			// 跟随系统
			if IspSettlement.SettlementInfo.Type == 1 {
				IspSettlementRate = 0
			} else {
				IspSettlementRate = IspSettlement.SettlementInfo.Rate
			}
		} else {
			// 自己设置
			IspSettlementRate = IspSettlement.SettlementRate
		}

		IspSettlementObject = IspSettlement.SettlementObject
	} else {
		IspSettlementObject = "TECHNICIAN"
	}

	// 重新判断下技师
	if !g.IsEmpty(in.TechnicianIds) {
		Config, err = service.BasicsConfig().GetConfigByGroup(ctx, &input_basics.GetConfigInp{
			Group: "spaordersetting",
		})
		if err != nil {
			return
		}
		ServiceTimeDuration := Config.List["serviceTimeDuration"]
		OutWorkTimeDuration := Config.List["outWorkTimeDuration"]
		OrderMode := Config.List["orderMode"]
		if models.ServiceType == 1 {
			BeforeTime = gvar.New(ServiceTimeDuration).Int()
		} else {
			BeforeTime = gvar.New(ServiceTimeDuration).Int() + gvar.New(OutWorkTimeDuration).Int()
		}
		StartTime := gtime.New(models.BookStartTime).Add(time.Duration(-BeforeTime) * gtime.M).Timestamp()
		for _, Technician := range strings.Split(in.TechnicianIds, ",") {
			CantOrderNum = 0
			if !g.IsEmpty(Technician) {
				TechnicianId, _ := strconv.ParseInt(Technician, 10, 64)
				if err = dao.SpaTechnician.Ctx(ctx).WherePri(TechnicianId).Scan(&TechnicianInfo); err != nil {
					return
				}
				if gvar.New(OrderMode).Int() == 2 {
					OrderIds, _ := dao.SpaOrderTechnician.Ctx(ctx).Where(dao.SpaOrderTechnician.Columns().TechnicianId, TechnicianId).Array(dao.SpaOrderTechnician.Columns().OrderId)
					if err = dao.SpaOrder.Ctx(ctx).Where(dao.SpaOrder.Columns().BookDate, models.BookDate).WhereIn(dao.CarOrder.Columns().Id, OrderIds).WhereNot(dao.SpaOrder.Columns().Id, in.Id).WhereIn(dao.SpaOrder.Columns().OrderStatus, g.Slice{"WAIT_SERVE", "SERVING"}).Scan(&CheckOrderList); err != nil {
						return
					}
					for _, v := range CheckOrderList {
						if v.ServiceType == 1 {
							OrderBeforeTime = gvar.New(ServiceTimeDuration).Int()
						} else {
							OrderBeforeTime = gvar.New(ServiceTimeDuration).Int() + gvar.New(OutWorkTimeDuration).Int()
						}
						OrderStartTime := gtime.New(v.BookStartTime).Add(time.Duration(-OrderBeforeTime) * gtime.M).Timestamp()
						if gtime.New(v.BookEndTime).Timestamp() <= StartTime || OrderStartTime >= gtime.New(models.BookEndTime).Timestamp() {
						} else {
							CantOrderNum++
						}
					}
				} else {
					if TechnicianInfo.Status == 2 {
						CantOrderNum++
					}
				}
				if CantOrderNum > 0 {
					err = gerror.New(fmt.Sprintf("技师%s不可派单，请重新选择", TechnicianInfo.Nickname))
					return
				}
			}
		}
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		if _, err = s.Model(ctx).
			WherePri(in.Id).Data(input_spa.SpaOrderDispatchInp{
			DispatchStatus:     "DONE",
			DispatchTime:       gtime.Now(),
			DispatchOperatorId: in.DispatchOperatorId,
			DispatchDesc:       in.DispatchDesc,
			TechnicianIds:      in.TechnicianIds,
		}).OmitEmptyData().Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		if _, err = dao.SpaOrderGoods.Ctx(ctx).TX(tx).Where(dao.SpaOrderGoods.Columns().OrderId, in.Id).Update(g.MapStrAny{
			dao.SpaOrderGoods.Columns().DispatchStatus:     "DONE",
			dao.SpaOrderGoods.Columns().DispatchTime:       gtime.Now(),
			dao.SpaOrderGoods.Columns().DispatchOperatorId: in.DispatchOperatorId,
			dao.SpaOrderGoods.Columns().DispatchDesc:       in.DispatchDesc,
			dao.SpaOrderGoods.Columns().TechnicianIds:      in.TechnicianIds,
		}); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     in.Id,
			OrderStatus: "WAIT_SERVE",
			ActionWay:   "DISPATCH",
			Remark:      "店长派单",
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		// 每次调度，需重新计算技师订单金额
		preTechnicianOrderAmount := format.Round2Float64(models.OrderAmount / float64(models.GoodsNum))
		preTechnicianCouponAmount := format.Round2Float64(models.CouponAmount / float64(models.GoodsNum))
		preTechnicianBalAmount := format.Round2Float64(models.BalAmount / float64(models.GoodsNum))

		// 存订单技师表
		// 记录结算比例和金额
		if !g.IsEmpty(in.TechnicianIds) {
			for _, Technician := range strings.Split(in.TechnicianIds, ",") {
				if !g.IsEmpty(Technician) {
					TechnicianId, _ := strconv.ParseInt(Technician, 10, 64)
					_ = dao.SpaTechnician.Ctx(ctx).WithAll().WherePri(TechnicianId).Scan(&TechnicianSettlement)
					var SettlementRate float64
					if TechnicianSettlement.SettlementType == 1 {
						// 跟随系统
						if TechnicianSettlement.SettlementInfo.Type == 1 {
							SettlementRate = 0
						} else {
							SettlementRate = TechnicianSettlement.SettlementInfo.Rate
						}
					} else {
						// 自己设置
						SettlementRate = TechnicianSettlement.SettlementRate
					}

					if IspSettlementObject == "TECHNICIAN" {
						ActualSettlementRate = SettlementRate
						ActualSettlementType = TechnicianSettlement.SettlementInfo.Type
						ActualSettlementCycle = TechnicianSettlement.SettlementInfo.Cycle
						ActualSettlementCost = TechnicianSettlement.SettlementInfo.Cost
					} else {
						ActualSettlementRate = IspSettlementRate
						ActualSettlementType = IspSettlement.SettlementInfo.Type
						ActualSettlementCycle = IspSettlement.SettlementInfo.Cycle
						ActualSettlementCost = IspSettlement.SettlementInfo.Cost
					}

					OrderTechnicianInfo = append(OrderTechnicianInfo, &entity.SpaOrderTechnician{
						IspId:            models.IspId,
						OrderId:          int64(in.Id),
						OrderGoodsId:     OrderGoods.Id,
						TechnicianId:     TechnicianId,
						OrderAmount:      preTechnicianOrderAmount,
						CouponAmount:     preTechnicianCouponAmount,
						BalAmount:        preTechnicianBalAmount,
						SettlementObject: IspSettlementObject,
						SettlementRate:   ActualSettlementRate,
						SettlementStatus: "WAIT",
						SettlementType:   ActualSettlementType,
						SettlementCycle:  ActualSettlementCycle,
						SettlementCost:   ActualSettlementCost,
					})

					// 更新技师预定量和预定金额
					if _, err = dao.SpaTechnician.Ctx(ctx).Where(dao.SpaTechnician.Columns().Id, TechnicianId).Update(g.MapStrAny{
						dao.SpaTechnician.Columns().TotalOrderNum:    gdb.Raw(fmt.Sprintf("total_order_num+%d", 1)),
						dao.SpaTechnician.Columns().TotalOrderAmount: gdb.Raw(fmt.Sprintf("total_order_amount+%f", models.OrderAmount/float64(models.GoodsNum))),
						dao.SpaTechnician.Columns().PayOrderNum:      gdb.Raw(fmt.Sprintf("pay_order_num+%d", 1)),
						dao.SpaTechnician.Columns().PayOrderAmount:   gdb.Raw(fmt.Sprintf("pay_order_amount+%f", models.OrderAmount/float64(models.GoodsNum))),
					}); err != nil {
						err = gerror.Wrap(err, "更新技师信息失败，请稍后重试！")
						return
					}
				}
			}
		}
		if !g.IsEmpty(OrderTechnicianInfo) {
			if _, err = dao.SpaOrderTechnician.Ctx(ctx).Where(dao.SpaOrderTechnician.Columns().OrderId, in.Id).Delete(); err != nil {
				err = gerror.Wrap(err, "清理旧数据失败，请稍后重试！")
				return
			}
			if _, err = dao.SpaOrderTechnician.Ctx(ctx).OmitEmptyData().Insert(OrderTechnicianInfo); err != nil {
				return err
			}
		} else {
			if _, err = dao.SpaOrderTechnician.Ctx(ctx).Where(dao.SpaOrderTechnician.Columns().OrderId, in.Id).Delete(); err != nil {
				err = gerror.Wrap(err, "清理旧数据失败，请稍后重试！")
				return
			}
		}

		return
	})

}

// TechnicianOrderList 结算订单列表
func (s *sSpaOrder) TechnicianOrderList(ctx context.Context, in *input_spa.SettleSpaOrderTechnicianListInp) (list []*input_spa.SettleSpaOrderTechnicianListModel, totalCount int, err error) {
	mod := dao.SpaOrderTechnician.Ctx(ctx).Safe().WithAll()

	mod = mod.Fields(input_spa.SettleSpaOrderTechnicianListModel{})

	if !g.IsEmpty(in.SettlementOrderId) {
		mod = mod.Where(dao.SpaOrderTechnician.Columns().SettlementOrderId, in.SettlementOrderId)
	}

	if !g.IsEmpty(in.OrderSn) {
		var OrderIds []int
		columns, _ := dao.SpaOrder.Ctx(ctx).
			Fields(dao.SpaOrder.Columns().Id).
			WhereLike(dao.SpaOrder.Columns().OrderSn, "%"+in.OrderSn+"%").
			Array()
		OrderIds = g.NewVar(columns).Ints()
		mod = mod.WhereIn(dao.SpaOrderTechnician.Columns().OrderId, OrderIds)
	}

	mod = mod.Page(in.Page, in.PerPage)

	mod = mod.OrderDesc(dao.SpaOrderTechnician.Columns().Id)
	//mod = mod.Hook(hook2.PmsFindLanguageValueHook)

	if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
		err = gerror.Wrap(err, "获取结算订单列表失败，请稍后重试！")
		return
	}
	return
}

func (s *sSpaOrder) GoOut(ctx context.Context, in *input_spa.SpaOrderGoOutInp) (err error) {

	var models *entity.SpaOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.ServiceType != 2 {
		err = gerror.New("服务方式不正确")
		return
	}

	if models.OrderStatus != "WAIT_SERVE" {
		err = gerror.New("订单状态不正确")
		return
	}

	if models.DispatchStatus != "DONE" {
		err = gerror.New("调度状态不正确")
		return
	}

	if !g.IsEmpty(models.TechnicianGoTime) {
		err = gerror.New("技师已出发")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		if _, err = s.Model(ctx).
			WherePri(in.Id).Data(input_spa.SpaOrderGoOutFields{
			TechnicianGoTime: gtime.Now(),
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		if _, err = dao.SpaOrderGoods.Ctx(ctx).Where(dao.SpaOrderGoods.Columns().OrderId, in.Id).Update(g.MapStrAny{
			dao.SpaOrderGoods.Columns().TechnicianGoTime: gtime.Now(),
		}); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     in.Id,
			OrderStatus: "WAIT_SERVE",
			ActionWay:   "OUT",
			Remark:      "技师出发",
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		// 技师状态改为工作中
		// 获取关联订单技师ids
		orderTechnicianIds, _ := service.SpaOrderTechnician().GetTechnicianIds(ctx, in.Id)
		if _, err = dao.SpaTechnician.Ctx(ctx).
			WhereIn(dao.SpaTechnician.Columns().Id, orderTechnicianIds).
			Data(g.MapStrAny{
				dao.SpaTechnician.Columns().WorkStatus: "WORKING",
			}).Update(); err != nil {
			err = gerror.Wrap(err, "修改技师工作状态失败，请稍后重试！")
			return
		}

		return
	})

}

func (s *sSpaOrder) StartService(ctx context.Context, in *input_spa.SpaOrderStartServiceInp) (err error) {

	var models *entity.SpaOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "WAIT_SERVE" {
		err = gerror.New("订单状态不正确")
		return
	}

	if models.DispatchStatus != "DONE" {
		err = gerror.New("调度状态不正确")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		if _, err = s.Model(ctx).
			WherePri(in.Id).Data(input_spa.SpaOrderStartServiceFields{
			OrderStatus:     "SERVING",
			ActualStartTime: gtime.Now(),
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		if _, err = dao.SpaOrderGoods.Ctx(ctx).Where(dao.SpaOrderGoods.Columns().OrderId, in.Id).Update(g.MapStrAny{
			dao.SpaOrderGoods.Columns().OrderStatus:     "SERVING",
			dao.SpaOrderGoods.Columns().ActualStartTime: gtime.Now(),
		}); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     in.Id,
			OrderStatus: "SERVING",
			ActionWay:   "SERVING",
			Remark:      "按摩服务开始",
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		// 技师状态改为工作中
		// 获取关联订单技师ids
		orderTechnicianIds, _ := service.SpaOrderTechnician().GetTechnicianIds(ctx, in.Id)
		if _, err = dao.SpaTechnician.Ctx(ctx).
			WhereIn(dao.SpaTechnician.Columns().Id, orderTechnicianIds).
			Data(g.MapStrAny{
				dao.SpaTechnician.Columns().WorkStatus: "WORKING",
			}).Update(); err != nil {
			err = gerror.Wrap(err, "修改技师工作状态失败，请稍后重试！")
			return
		}

		return
	})

}

func (s *sSpaOrder) EndService(ctx context.Context, in *input_spa.SpaOrderEndServiceInp) (err error) {

	var (
		models              *entity.SpaOrder
		OrderTechnicianInfo *entity.SpaOrderTechnician
		TechnicianInfo      *entity.SpaTechnician
	)
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "SERVING" {
		err = gerror.New("订单状态不正确")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		if _, err = s.Model(ctx).
			WherePri(in.Id).Data(input_spa.SpaOrderEndServiceFields{
			OrderStatus:   "DONE",
			ActualEndTime: gtime.Now(),
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		if _, err = dao.SpaOrderGoods.Ctx(ctx).Where(dao.SpaOrderGoods.Columns().OrderId, in.Id).Update(g.MapStrAny{
			dao.SpaOrderGoods.Columns().OrderStatus:   "DONE",
			dao.SpaOrderGoods.Columns().ActualEndTime: gtime.Now(),
		}); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		if _, err = dao.SpaOrderTechnician.Ctx(ctx).Where(dao.SpaOrderTechnician.Columns().OrderId, in.Id).Update(g.MapStrAny{
			dao.SpaOrderTechnician.Columns().ActualEndTime: gtime.Now(),
		}); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     in.Id,
			OrderStatus: "DONE",
			ActionWay:   "DONE",
			Remark:      "按摩服务结束",
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		// 技师状态改为可约
		// 获取关联订单技师ids
		orderTechnicianIds, _ := service.SpaOrderTechnician().GetTechnicianIds(ctx, in.Id)
		if _, err = dao.SpaTechnician.Ctx(ctx).
			WhereIn(dao.SpaTechnician.Columns().Id, orderTechnicianIds).
			Data(g.MapStrAny{
				dao.SpaTechnician.Columns().WorkStatus: "CANORDER",
			}).Update(); err != nil {
			err = gerror.Wrap(err, "修改技师工作状态失败，请稍后重试！")
			return
		}

		// 记录分佣
		for _, orderTechnicianId := range orderTechnicianIds {
			_ = dao.SpaOrderTechnician.Ctx(ctx).Where(dao.SpaOrderTechnician.Columns().OrderId, in.Id).Where(dao.SpaOrderTechnician.Columns().TechnicianId, orderTechnicianId).Scan(&OrderTechnicianInfo)
			_ = dao.SpaTechnician.Ctx(ctx).WherePri(orderTechnicianId).Scan(&TechnicianInfo)
			cost := OrderTechnicianInfo.SettlementCost
			settlementAmount := OrderTechnicianInfo.OrderAmount
			if !g.IsEmpty(cost) {
				costArr := strings.Split(cost, ",")
				constIsCoupon := false
				constIsBal := false
				for _, costItem := range costArr {
					if gvar.New(costItem).Int() == 1 {
						constIsCoupon = true
						//settlementAmount = settlementAmount - OrderTechnicianInfo.CouponAmount
					}
					if gvar.New(costItem).Int() == 2 {
						constIsBal = true
						//settlementAmount = settlementAmount - OrderTechnicianInfo.BalAmount
					}
				}
				if !constIsCoupon {
					settlementAmount = settlementAmount - models.CouponAmount
				}
				if !constIsBal {
					settlementAmount = settlementAmount - models.BalAmount
				}
			}
			settlementAmount = decimal.NewFromFloat(settlementAmount).Mul(decimal.NewFromFloat(OrderTechnicianInfo.SettlementRate)).Div(decimal.NewFromFloat(100)).Round(0).InexactFloat64()
			if _, err = dao.SpaOrderTechnician.Ctx(ctx).TX(tx).Data(g.Map{
				dao.SpaOrderTechnician.Columns().SettlementAmount: settlementAmount,
			}).Where(dao.SpaOrderTechnician.Columns().Id, OrderTechnicianInfo.Id).Update(); err != nil {
				return
			}
		}

		// 转发到返利队列
		_ = rabbitmq.SendMqMessage(ctx, &rabbitmq.SendMqMessageParams{
			ExchangeName: consts.RabbitMQExchangeName,
			QueueName:    consts.RabbitMQQueueNameRebate,
			DataByte:     gvar.New(models.OrderSn).Bytes(),
			Header:       nil,
		})
		_ = rabbitmq.SendMqMessage(ctx, &rabbitmq.SendMqMessageParams{
			ExchangeName: consts.RabbitMQExchangeName,
			QueueName:    consts.RabbitMQQueueNameExp,
			DataByte:     gvar.New(models.OrderSn).Bytes(),
			Header:       nil,
		})

		return
	})

}

// CancelPay 取消订单
func (s *sSpaOrder) CancelPay(ctx context.Context, in *input_spa.SpaOrderCancelPayInp) (err error) {

	var models *entity.SpaOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.PayStatus != "HAVE_PAID" {
		err = gerror.New("订单支付状态不正确")
		return
	}

	if models.OrderStatus == "SERVING" || models.OrderStatus == "DONE" {
		err = gerror.New("订单状态不正确")
		return
	}

	if models.AdminCancelNum > 0 {
		err = gerror.New("后台不可多次退款")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {

		// 确认失败、全额退款
		// 计算退款金额
		var (
			Transaction       []*entity.PmsTransaction
			TransactionRefund []*entity.PmsTransactionRefund
			CancelFee         float64 // 退款手续费
			RefundBalance     float64 // 可退款积分
			RefundFee         float64 // 第三方支付
		)
		CancelFee = models.OrderAmount - models.CouponAmount - in.RefundMoney
		CancelFeeCalc := CancelFee
		if err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(dao.PmsTransaction.Columns().PayStatus, "DONE").Where(dao.PmsTransaction.Columns().OrderSn, models.OrderSn).Scan(&Transaction); err != nil {
			return
		}
		if err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).Where(dao.PmsTransactionRefund.Columns().OrderSn, models.OrderSn).Scan(&TransactionRefund); err != nil {
			return
		}

		for _, v := range Transaction {
			// 可退款金额
			Refundable := v.Amount - v.RefundAmount
			if v.PayType == "BAL" {
				if g.IsEmpty(CancelFeeCalc) {
					RefundBalance += Refundable
				} else if CancelFeeCalc > Refundable {
					RefundBalance += 0
					CancelFeeCalc = CancelFeeCalc - Refundable
				} else {
					RefundBalance += Refundable - CancelFeeCalc
					CancelFeeCalc = 0
				}
			} else if v.PayType == "COUPON" {

			} else {
				if g.IsEmpty(CancelFeeCalc) {
					RefundFee += Refundable
				} else if CancelFeeCalc > Refundable {
					RefundFee += 0
					CancelFeeCalc = CancelFeeCalc - Refundable
				} else {
					RefundFee += Refundable - CancelFeeCalc
					CancelFeeCalc = 0
				}
			}
		}
		// 退款金额
		RefundAmount := RefundBalance + RefundFee

		OrderTotalRefundAmount := RefundAmount + models.RefundAmount
		OrderTotalRefundBalance := RefundBalance + models.RefundBalAmount

		AdminOrderTotalRefundAmount := RefundAmount + models.AdminRefundAmount
		AdminOrderTotalRefundBalance := RefundBalance + models.AdminRefundBalAmount

		// 修改订单状态
		RefundStatus := "DONE"
		if models.OrderAmount > OrderTotalRefundAmount {
			RefundStatus = "PART"
		}
		if in.RefundType == 1 {
			// 仅退款
			if _, err = s.Model(ctx).TX(tx).
				WherePri(in.Id).Data(g.MapStrAny{
				//dao.SpaOrder.Columns().RefundFee:          CancelFee,
				dao.SpaOrder.Columns().RefundAmount:         OrderTotalRefundAmount,
				dao.SpaOrder.Columns().RefundBalAmount:      OrderTotalRefundBalance,
				dao.SpaOrder.Columns().AdminRefundAmount:    AdminOrderTotalRefundAmount,
				dao.SpaOrder.Columns().AdminRefundBalAmount: AdminOrderTotalRefundBalance,
				dao.SpaOrder.Columns().RefundCouponAmount:   0,
				dao.SpaOrder.Columns().RefundStatus:         RefundStatus,
				dao.SpaOrder.Columns().RefundTime:           gtime.Now(),
				dao.SpaOrder.Columns().AdminCancelReason:    in.AdminCancelReason,
			}).Update(); err != nil {
				err = gerror.Wrap(err, "操作失败，请稍后重试！")
				return
			}

			// 更新服务预定量和预定金额
			if _, err = dao.SpaService.Ctx(ctx).TX(tx).Where(dao.SpaService.Columns().Id, models.ServiceId).Update(g.MapStrAny{
				dao.SpaService.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新服务信息失败，请稍后重试！")
				return
			}

			// 更新项目预定量和预定金额
			if _, err = dao.SpaServiceGoods.Ctx(ctx).TX(tx).Where(dao.SpaServiceGoods.Columns().Id, models.GoodsId).Update(g.MapStrAny{
				dao.SpaServiceGoods.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新项目信息失败，请稍后重试！")
				return
			}

			// 更新技师预定量和预定金额
			if !g.IsEmpty(models.TechnicianIds) {
				for _, Technician := range strings.Split(models.TechnicianIds, ",") {
					if !g.IsEmpty(Technician) {
						TechnicianId, _ := strconv.ParseInt(Technician, 10, 64)
						// 更新技师预定量和预定金额
						if _, err = dao.SpaTechnician.Ctx(ctx).Where(dao.SpaTechnician.Columns().Id, TechnicianId).Update(g.MapStrAny{
							dao.SpaTechnician.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount/float64(models.GoodsNum))),
						}); err != nil {
							err = gerror.Wrap(err, "更新技师信息失败，请稍后重试！")
							return
						}
					}
				}
			}
		} else {
			// 退款并取消
			if _, err = s.Model(ctx).TX(tx).
				WherePri(in.Id).Data(g.MapStrAny{
				//dao.SpaOrder.Columns().RefundFee:          CancelFee,
				dao.SpaOrder.Columns().RefundAmount:         OrderTotalRefundAmount,
				dao.SpaOrder.Columns().RefundBalAmount:      OrderTotalRefundBalance,
				dao.SpaOrder.Columns().AdminRefundAmount:    AdminOrderTotalRefundAmount,
				dao.SpaOrder.Columns().AdminRefundBalAmount: AdminOrderTotalRefundBalance,
				dao.SpaOrder.Columns().RefundCouponAmount:   0,
				dao.SpaOrder.Columns().RefundStatus:         RefundStatus,
				dao.SpaOrder.Columns().RefundTime:           gtime.Now(),
				dao.SpaOrder.Columns().OrderStatus:          "CANCEL",
				dao.SpaOrder.Columns().PayStatus:            "REFUND",
				dao.SpaOrder.Columns().AdminCancelReason:    in.AdminCancelReason,
				dao.SpaOrder.Columns().CancelTime:           gtime.Now(),
			}).Update(); err != nil {
				err = gerror.Wrap(err, "操作失败，请稍后重试！")
				return
			}

			// 更新服务预定量和预定金额
			if _, err = dao.SpaService.Ctx(ctx).TX(tx).Where(dao.SpaService.Columns().Id, models.ServiceId).Update(g.MapStrAny{
				dao.SpaService.Columns().PayOrderNum:    gdb.Raw("pay_order_num-1"),
				dao.SpaService.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新服务信息失败，请稍后重试！")
				return
			}

			// 更新项目预定量和预定金额
			if _, err = dao.SpaServiceGoods.Ctx(ctx).TX(tx).Where(dao.SpaServiceGoods.Columns().Id, models.GoodsId).Update(g.MapStrAny{
				dao.SpaServiceGoods.Columns().PayOrderNum:    gdb.Raw(fmt.Sprintf("pay_order_num-%d", models.GoodsNum)),
				dao.SpaServiceGoods.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新项目信息失败，请稍后重试！")
				return
			}

			// 更新技师预定量和预定金额
			if !g.IsEmpty(models.TechnicianIds) {
				for _, Technician := range strings.Split(models.TechnicianIds, ",") {
					if !g.IsEmpty(Technician) {
						TechnicianId, _ := strconv.ParseInt(Technician, 10, 64)
						// 更新技师预定量和预定金额
						if _, err = dao.SpaTechnician.Ctx(ctx).Where(dao.SpaTechnician.Columns().Id, TechnicianId).Update(g.MapStrAny{
							dao.SpaTechnician.Columns().PayOrderNum:    gdb.Raw(fmt.Sprintf("pay_order_num-%d", 1)),
							dao.SpaTechnician.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount/float64(models.GoodsNum))),
						}); err != nil {
							err = gerror.Wrap(err, "更新技师信息失败，请稍后重试！")
							return
						}
					}
				}
			}
		}

		if _, err = dao.SpaOrder.Ctx(ctx).TX(tx).WherePri(in.Id).Update(g.MapStrAny{
			dao.SpaOrder.Columns().AdminCancelNum: gdb.Raw("admin_cancel_num+1"),
		}); err != nil {
			err = gerror.Wrap(err, "更新失败，请稍后重试！")
			return
		}

		if RefundAmount > 0 {
			// 退款
			err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
				OrderSn:      models.OrderSn,
				RefundAmount: RefundAmount,
			}, tx)
			if err != nil {
				err = gerror.Wrap(err, "退款操作失败，请稍后重试！")
				return
			}
		}

		// 订单日志
		if _, err = dao.SpaOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.SpaOrderLog{
			OrderId:     int(in.Id),
			OrderStatus: models.OrderStatus,
			ActionWay:   "ADMIN_REFUND",
			Remark:      fmt.Sprintf("后台退款，原因：%s", in.AdminCancelReason),
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		if in.RefundType == 2 {
			// 订单日志
			if _, err = dao.SpaOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.SpaOrderLog{
				OrderId:     int(in.Id),
				OrderStatus: "CANCEL",
				ActionWay:   "CANCEL",
				Remark:      "后台订单取消",
				OperateType: "ADMIN",
				OperateId:   int(contexts.GetUserId(ctx)),
			}); err != nil {
				return err
			}
		}

		return
	})

}
